﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace Bamboo.Utils
{

    public static class XmlNodeExtend
    {
        /// <summary>
        /// 加载xml并返回根节点
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="rootNodeName"></param>
        /// <param name="encoding"></param>
        /// <param name="version"></param>
        /// <param name="standalone"></param>
        /// <returns></returns>
        public static XmlElement InitXml(this XmlDocument xml, string rootNodeName, string encoding = "GB2312", string version = "1.0", string standalone = null)
        {
            xml.AddDeclarationNode(version, encoding, standalone);
            return xml.AddRootNode(rootNodeName);
        }

        /// <summary>
        /// 获取属性值
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string GetAttrValue(this XmlNode node, string name, string defaultValue)
        {
            foreach (XmlAttribute attr in node.Attributes)
            {
                if (attr.Name == name)
                {
                    return attr.Value;
                }
            }
            return defaultValue;
        }

        /// <summary>
        /// 获取属性值（整形数）
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static int GetAttrValue(this XmlNode node, string name, int defaultValue)
        {
            string s = GetAttrValue(node, name, "");
            if (string.IsNullOrWhiteSpace(s)) return defaultValue;
            int v;
            if (int.TryParse(s, out v)) return v;
            else return defaultValue;
        }

        /// <summary>
        /// 获取属性值（数字）
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static decimal GetAttrValue(this XmlNode node, string name, decimal defaultValue)
        {
            string s = GetAttrValue(node, name, "");
            if (string.IsNullOrWhiteSpace(s)) return defaultValue;
            decimal v;
            if (decimal.TryParse(s, out v)) return v;
            else return defaultValue;
        }

        /// <summary>
        /// 获取属性值（布尔）
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static bool GetAttrValue(this XmlNode node, string name, bool defaultValue)
        {
            string s = GetAttrValue(node, name, "");
            if (string.IsNullOrWhiteSpace(s)) return defaultValue;
            s = s.ToLower();
            if (s == "true" || s == "1" || s == "y" || s == "yes") return true;
            else return false;
        }

        /// <summary>
        /// 获取子节点的值（文本）
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string GetSubNodeValue(this XmlNode node, string name, string defaultValue)
        {
            foreach (XmlNode subnode in node.ChildNodes)
            {
                if (subnode.Name == name)
                {
                    return subnode.InnerText;
                }
            }
            return defaultValue;
        }
        /// <summary>
        /// 获取子节点
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static XmlNode GetSubNode(this XmlNode node, string name)
        {
            foreach (XmlNode subnode in node.ChildNodes)
            {
                if (subnode.Name == name)
                {
                    return subnode;
                }
            }
            return null;
        }

        /// <summary>
        /// 设置属性值（字符串类型）
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        public static void SetAttrValue(this XmlNode node, string name, string value)
        {
            XmlAttribute attribute = node.Attributes[name];
            if (attribute == null)
            {
                attribute = node.OwnerDocument.CreateAttribute(name);
                node.Attributes.Append(attribute);
            }
            attribute.Value = value;
        }
        /// <summary>
        /// 删除某个属性
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        public static void RemoveAttr(this XmlNode node, string name)
        {
            XmlAttribute attribute = node.Attributes[name];
            if (attribute != null)
            {
                node.Attributes.Remove(attribute);
            }
        }

        /// <summary>
        /// 设置属性值，带URL
        /// </summary>
        /// <param name="node"></param>
        /// <param name="prefix"></param>
        /// <param name="localName"></param>
        /// <param name="namespaceURI"></param>
        /// <param name="value"></param>
        public static void SetAttrValueURI(this XmlNode node, string prefix, string localName, string namespaceURI,
            string value)
        {
            XmlAttribute attribute = node.Attributes[localName];
            if (attribute == null)
            {
                attribute = node.OwnerDocument.CreateAttribute(prefix, localName, namespaceURI);
                node.Attributes.Append(attribute);
            }
            attribute.Value = value;
        }
        /// <summary>
        /// 将XML写入文件
        /// </summary>
        /// <param name="xmlDoc"></param>
        /// <param name="fileName"></param>
        public static void SaveFile(this XmlDocument xmlDoc, string fileName)
        {
            using (FileStream fs = new FileStream(fileName, FileMode.Create))
            {
                xmlDoc.Save(fs);
                fs.Flush();
            }
        }
        /// <summary>
        /// 将XML内容转成字符串返回
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        public static string XmlToString(this XmlDocument xml)
        {
            using (MemoryStream s = new MemoryStream())
            {
                xml.Save(s);
                StreamReader sr = new StreamReader(s);
                s.Position = 0;
                return sr.ReadToEnd();
            }
        }
        /// <summary>
        /// 新增节点
        /// </summary>
        /// <param name="parentNode"></param>
        /// <param name="nodeName"></param>
        /// <param name="namespaceURI"></param>
        /// <returns></returns>
        public static XmlNode AddNode(this XmlNode parentNode, string nodeName, string namespaceURI = "")
        {
            XmlNode node = parentNode.OwnerDocument.CreateNode(XmlNodeType.Element, nodeName, namespaceURI);
            parentNode.AppendChild(node);
            return node;
        }
        /// <summary>
        /// 获取单个节点的值
        /// </summary>
        /// <param name="node"></param>
        /// <param name="xpath"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string SelectSingleNodeValue(this XmlNode node, string xpath, string defaultValue)
        {
            XmlNode res = node.SelectSingleNode(xpath);
            if (res == null)
                return defaultValue;
            else
                return res.Value;
        }
        /// <summary>
        /// 获取单个节点的值(整型)
        /// </summary>
        /// <param name="node"></param>
        /// <param name="xpath"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static int SelectSingleNodeValue(this XmlNode node, string xpath, int defaultValue)
        {
            string valueStr = node.SelectSingleNodeValue(xpath, "");
            int valueInt;
            if (int.TryParse(valueStr, out valueInt))
                return valueInt;
            else
                return defaultValue;
        }
        /// <summary>
        /// 根据xpath获取节点值，找不到则返回默认值
        /// </summary>
        /// <param name="node"></param>
        /// <param name="xpath"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static string GetXValue(this XmlNode node, string xpath, string defaultValue)
        {
            XmlNode res = node.SelectSingleNode(xpath);
            if (res == null)
                return defaultValue;
            else
            {
                if (res is XmlAttribute)
                    return res.Value;
                else
                    return res.InnerText;
            }
        }
        /// <summary>
        /// 对新建的xml文档添加声明节点
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="version"></param>
        /// <param name="encoding"></param>
        /// <param name="standalone"></param>
        /// <returns></returns>
        public static XmlDeclaration AddDeclarationNode(this XmlDocument xml, string version = "1.0", string encoding = "GBK", string standalone = null)
        {
            XmlDeclaration xmlDecl = xml.CreateXmlDeclaration(version, encoding, standalone);
            xml.AppendChild(xmlDecl);
            return xmlDecl;
        }
        /// <summary>
        /// 对新建的XML文档增加根节点
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="nodeName"></param>
        /// <returns></returns>
        public static XmlElement AddRootNode(this XmlDocument xml, string nodeName)
        {
            XmlElement rootNode = xml.CreateElement(nodeName);
            xml.AppendChild(rootNode);
            return rootNode;
        }
        /// <summary>
        /// 初始化一个新建的xml文档，添加声明节点和根节点，并返回根节点
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="rootNodeName"></param>
        /// <param name="encoding"></param>
        /// <param name="version"></param>
        /// <param name="standalone"></param>
        public static XmlElement Init(this XmlDocument xml, string rootNodeName, string encoding = "GB2312", string version = "1.0", string standalone = null)
        {
            xml.AddDeclarationNode(version, encoding, standalone);
            var rootNode = xml.AddRootNode(rootNodeName);
            return rootNode;
        }

        /// <summary>
        /// 将当前节点的完整结构拷贝到新的父节点之下
        /// </summary>
        /// <param name="node"></param>
        /// <param name="targetParentNode"></param>
        public static void CopyTo(this XmlNode node, XmlNode targetParentNode)
        {
            //创建当前节点
            XmlNode targetNode = targetParentNode.AddNode(node.Name);
            //拷贝当前节点值，如果有的话
            if (!string.IsNullOrWhiteSpace(node.Value))
            {
                targetNode.Value = node.Value;
            }
            //拷贝属性
            foreach (XmlAttribute item in node.Attributes)
            {
                targetNode.SetAttrValue(item.Name, item.Value);
            }
            //拷贝子结点
            foreach (XmlNode item in node.ChildNodes)
            {
                item.CopyTo(targetNode);
            }
        }
    }
}
